#include "app_device.h"
#include "app_mqtt.h"
#include "app_buffer.h"
#include "app_message.h"
#include "app_pool.h"
#include "app_common.h"
#include "log.h"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>

static device_t *device = NULL;
/**
 * @brief 初始化设备
 * @param 设备的文件地址
 * @return 设备结构体
 */
device_t *app_device_init(char *dev_file_name)
{
	device_t *dev = (device_t *)malloc(sizeof(device_t));
	if (dev == NULL)
	{
		log_error("device init error");
		return NULL;
	}
	dev->dev_file_name = dev_file_name;
	dev->dev_fd = open(dev_file_name, O_RDWR);
	if (dev->dev_fd < 0)
	{
		perror("打开设备文件失败");
		return NULL;
	}
	// 为预处理方法的初始值设置为NULL
	dev->post_read = NULL;
	dev->pre_write =NULL;
	// --
	// 缓冲区
	dev->up_buffer = app_buffer_init(1024);
	dev->down_buffer = app_buffer_init(1024);
	// 运行情况
	dev->is_running = 0;
	// 上次写入时间
	dev->last_write_ts_ms = 0;
	// 写入间隔
	dev->write_interval_ms = 200;

	device = dev;
	return dev;
}

/**
 * @brief 启动设备读取操作
 * //1 启动从蓝牙串口中读取数据 (上行线路开始)
 * //2 向消息队列模块中注册接收数据后的处理函数 （下行线路开始）
 *
 */
int app_device_start()
{
	if (device->is_running)
	{
		return 0;
	}


	// 1 启动从蓝牙串口中读取数据的线程 (上行线路开始)
	device->is_running = 1;
	int ret = pthread_create(&device->dev_read_thread, NULL, app_device_read, NULL);
	if (ret < 0)
	{
		perror("创建线程失败");
		return -1;
	}

	// 2 向消息队列模块中注册接收数据后的处理函数 （下行线路开始）
	app_mqtt_register_recv(app_device_receive_from_mqtt);

	
	return 0;
}

/**
 * @brief  从蓝牙芯片中读取数据（异步方法） 图中1号
 * 1  从蓝牙芯片中读取数据
 * 2  要做读后预处理 转换格式
 * 3  写入到上行缓冲区中
 * 4  安排线程池执行 后续工作（发送mqtt）
 */
void *app_device_read(void *arg)
{
	while (device->is_running)
	{
		// * 1  从蓝牙芯片中读取数据
		char data_buff[128] = {0};
		int read_size = read(device->dev_fd, data_buff, 128);
		if (read_size <= 0)
		{
			continue;
		}
		log_info("读取到数据");
		app_common_print_hex(data_buff, read_size);
		//* 2  要做读后预处理 转换格式
		if(device->post_read)
		{
			read_size = device->post_read(data_buff, read_size);
		}
		if (read_size <= 0)
		{
			continue;
		}
		//* 3  写入到上行缓冲区中
		int ret = app_buffer_write(device->up_buffer, data_buff, read_size);
		if (ret < 0)
		{
			log_error("写入上行缓冲区失败");
			continue;
		}

		//* 4  安排线程池执行 后续工作（发送mqtt）
		app_pool_register_task(app_device_send_to_mqtt, NULL);
	}

	return NULL;
}

/**
 * @brief 从缓冲区中读取数据写入到mqtt中（异步方法、线程池执行）图中2号
 * 1  从上行缓冲区中读取数据
 * 2  做数据格式转换 转json
 * 3  发送到mqtt中
 */
void *app_device_send_to_mqtt(void *arg)
{
	// * 1  从上行缓冲区中读取数据
	char data_buff[128] = {0};
	int read_size = app_buffer_read(device->up_buffer, data_buff, 128);

 	//* 2  做数据格式转换 转json
	char *json= app_message_bytes2json(data_buff, read_size);
	if(json==NULL)
	{
		log_error("转换json失败");
		return NULL;
	}

	// * 3  发送到mqtt中
	int ret= app_mqtt_send(json,strlen(json));
	if(ret<0)
	{
		log_error("发送mqtt失败");
		return NULL;
	}
	return NULL;

}

/**
 * @brief 从mqtt中接收数据到缓冲区中 （注册给消息队列模块） 图中3号
 *  1  把从mqtt中接收的json进行 转换 字节数组
 *  2  写入到下行缓冲区中
 *  3  安排线程池行程执行后续工作（写入蓝牙芯片）
 */
int app_device_receive_from_mqtt(char *json_data, int json_data_len)
{
   //  1  把从mqtt中接收的json进行 转换 字节数组
	char data_buff[128]={0};
    int data_len= app_message_json2bytes(json_data,data_buff,128);
   
   // 2  写入到下行缓冲区中
   int ret= app_buffer_write(device->down_buffer,data_buff,data_len);
   if(ret<0)
   {
	   log_error("写入下行缓冲区失败");
	   return -1;
   }
   //3    安排线程池行程执行后续工作（写入蓝牙芯片）
	app_pool_register_task(app_device_write, NULL);

	return 0;
}

/**
 * @brief 从下行缓冲区向蓝牙芯片中写入数据（异步方法 线程池x执行） 图中4号
 *  //1  从下行缓冲区中读取数据
 *  //2  如果有数据则进行写前预处理
 *  //3  写入到蓝牙芯片中(串口文件)
 */
void *app_device_write(void *arg)
{
	//1  从下行缓冲区中读取数据
	char data_buff[128]={0};

	int data_size= app_buffer_read(device->down_buffer,data_buff,128);
	log_info("从缓冲区读取数据:");
	app_common_print_hex(data_buff,data_size);
   //2  如果有数据则进行写前预处理
	if(data_size==0)
	{
		return NULL;
	}
	if(device->pre_write)
	{
		data_size=device->pre_write(data_buff,data_size);
	}
    //3  写入到蓝牙芯片中(串口文件)
	//写入数据之前要控制频率  必须达到间隔才能写入
	long long now_ts_ms=app_common_getcurtime_ms();
	log_info("系统时间：%lld",now_ts_ms);
	if(device->last_write_ts_ms>0 ){
		int cur_interval_ms=now_ts_ms -device->last_write_ts_ms ; //当前间隔=当前时间-上次写入时间
		if(cur_interval_ms<device->write_interval_ms) //如果当前间隔小于要求间隔时间
		{
			usleep((device->write_interval_ms - cur_interval_ms)*1000 ); //要求间隔-当前间隔=需要等待的时间
		}
	}
	log_info("写入数据:");
	app_common_print_hex(data_buff,data_size);
	int ret=write(device->dev_fd,data_buff,data_size);
	if(ret<0)
	{
		log_error("写入设备数据失败");
		return NULL;
	}
	return NULL;
}

/**
 * @brief 停止设备读取操作 销毁设备
 *
 */
void app_device_destroy()
{
	//结束读取操作
	device->is_running=0;
	pthread_cancel(device->dev_read_thread) ;

	 app_buffer_destroy(device->up_buffer);
	 app_buffer_destroy(device->down_buffer);

	close(device->dev_fd);

	free(device);



}